"""Test power stat validation."""

import pytest

from homeassistant.components.energy import validate
from homeassistant.components.energy.data import EnergyManager
from homeassistant.const import UnitOfPower
from homeassistant.core import HomeAssistant

POWER_UNITS_STRING = ", ".join(tuple(UnitOfPower))


@pytest.fixture(autouse=True)
async def setup_energy_for_validation(
    mock_energy_manager: EnergyManager,
) -> EnergyManager:
    """Ensure energy manager is set up for validation tests."""
    return mock_energy_manager


async def test_validation_grid_power_valid(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with valid power sensor."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.grid_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.grid_power",
        "1.5",
        {
            "device_class": "power",
            "unit_of_measurement": UnitOfPower.KILO_WATT,
            "state_class": "measurement",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [[]],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_wrong_unit(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with power sensor having wrong unit."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.grid_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.grid_power",
        "1.5",
        {
            "device_class": "power",
            "unit_of_measurement": "beers",
            "state_class": "measurement",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "entity_unexpected_unit_power",
                    "affected_entities": {("sensor.grid_power", "beers")},
                    "translation_placeholders": {"power_units": POWER_UNITS_STRING},
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_wrong_state_class(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with power sensor having wrong state class."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.grid_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.grid_power",
        "1.5",
        {
            "device_class": "power",
            "unit_of_measurement": UnitOfPower.KILO_WATT,
            "state_class": "total_increasing",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "entity_unexpected_state_class",
                    "affected_entities": {("sensor.grid_power", "total_increasing")},
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_entity_missing(
    hass: HomeAssistant, mock_energy_manager
) -> None:
    """Test validating grid with missing power sensor."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.missing_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "statistics_not_defined",
                    "affected_entities": {("sensor.missing_power", None)},
                    "translation_placeholders": None,
                },
                {
                    "type": "entity_not_defined",
                    "affected_entities": {("sensor.missing_power", None)},
                    "translation_placeholders": None,
                },
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_entity_unavailable(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with unavailable power sensor."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.unavailable_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set("sensor.unavailable_power", "unavailable", {})

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "entity_unavailable",
                    "affected_entities": {("sensor.unavailable_power", "unavailable")},
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_entity_non_numeric(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with non-numeric power sensor."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.non_numeric_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.non_numeric_power",
        "not_a_number",
        {
            "device_class": "power",
            "unit_of_measurement": UnitOfPower.KILO_WATT,
            "state_class": "measurement",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "entity_state_non_numeric",
                    "affected_entities": {("sensor.non_numeric_power", "not_a_number")},
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_wrong_device_class(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with power sensor having wrong device class."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.wrong_device_class_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.wrong_device_class_power",
        "1.5",
        {
            "device_class": "energy",
            "unit_of_measurement": "kWh",
            "state_class": "measurement",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "entity_unexpected_device_class",
                    "affected_entities": {
                        ("sensor.wrong_device_class_power", "energy")
                    },
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_different_units(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with power sensors using different valid units."""
    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.power_watt",
                        },
                        {
                            "stat_rate": "sensor.power_milliwatt",
                        },
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )
    hass.states.async_set(
        "sensor.power_watt",
        "1500",
        {
            "device_class": "power",
            "unit_of_measurement": UnitOfPower.WATT,
            "state_class": "measurement",
        },
    )
    hass.states.async_set(
        "sensor.power_milliwatt",
        "1500000",
        {
            "device_class": "power",
            "unit_of_measurement": UnitOfPower.MILLIWATT,
            "state_class": "measurement",
        },
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [[]],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_external_statistics(
    hass: HomeAssistant, mock_energy_manager, mock_get_metadata
) -> None:
    """Test validating grid with external power statistics (non-entity)."""
    mock_get_metadata["external:power_stat"] = None

    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "external:power_stat",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "statistics_not_defined",
                    "affected_entities": {("external:power_stat", None)},
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }


async def test_validation_grid_power_recorder_untracked(
    hass: HomeAssistant, mock_energy_manager, mock_is_entity_recorded, mock_get_metadata
) -> None:
    """Test validating grid with power sensor not tracked by recorder."""
    mock_is_entity_recorded["sensor.untracked_power"] = False

    await mock_energy_manager.async_update(
        {
            "energy_sources": [
                {
                    "type": "grid",
                    "flow_from": [],
                    "flow_to": [],
                    "power": [
                        {
                            "stat_rate": "sensor.untracked_power",
                        }
                    ],
                    "cost_adjustment_day": 0.0,
                }
            ]
        }
    )

    result = await validate.async_validate(hass)
    assert result.as_dict() == {
        "energy_sources": [
            [
                {
                    "type": "recorder_untracked",
                    "affected_entities": {("sensor.untracked_power", None)},
                    "translation_placeholders": None,
                }
            ]
        ],
        "device_consumption": [],
        "device_consumption_water": [],
    }
